package br.unb.core.message;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketTimeoutException;
import javax.swing.text.DefaultStyledDocument;

import br.unb.utils.Console;
import br.unb.utils.ConsoleInterface;
import br.unb.utils.Resource;

/**
 *
 * @author spider
 */
public class Socket implements ConsoleInterface {

    /*Output port for comunication between two hosts, has no timeout*/
    public static final int CONTROL_PORT = 9999;
    /*Input port for comunication between two hosts, has a timeout*/
    public static final int DISPATCHER_PORT = 8888;
    /*Output port for comunication between two hosts, has no timeout*/
    public static final int STATUS_PORT = 7777;
    /*Max packet length to be received*/
    public static final int MAX_LEN = 8100;
    /**/
    public static final boolean DEBUG = true;
    public byte[] buffer = new byte[MAX_LEN];
    public DatagramSocket socket;
    public DatagramPacket lastInPacket;
    //
    String name;

    public void setName(String SocketName) {
        this.name = SocketName;
    }
    //

    public void send(Message message, InetAddress dst, int port) {
        printError(
                Resource.getString("Send:")//14 chars wide
                + dst.getHostAddress()
                + ":" + Integer.toString(port) + ". ",
                message);
        try {
            byte[] buffer = message.getData();
            DatagramPacket packet = new DatagramPacket(buffer, buffer.length, dst, port);
            this.socket.send(packet);
        } catch (SocketTimeoutException ex) {
            Console.showMessageDialog(
                    Resource.getString("SOCKET_TIMEOUT") + ex.getMessage());
        } catch (IOException ex) {
            Console.showMessageDialog(
                    Resource.getString("NETWORK_DISCONNECTED") + ex.getMessage());
        }
    }

    /**
     * 
     * @param message Mesage to be sent
     */
    public Message receive() {
        Message recMessage = null;
        try {
            byte[] buffer = this.buffer;
            DatagramPacket packet = new DatagramPacket(buffer, buffer.length);
            this.socket.receive(packet);
            lastInPacket = packet; //Only used on DispacherSocket
            recMessage = new Message(buffer);
            printError(
                    Resource.getString("Receive:")//14 chars wide
                    + packet.getAddress().getHostAddress()
                    + ":" + packet.getPort() + ". ",
                    recMessage);

        } catch (SocketTimeoutException ex) {
            Console.showMessageDialog(
                    Resource.getString("SOCKET_TIMEOUT") + ex.getMessage());
        } catch (IOException ex) {
            Console.showMessageDialog(
                    Resource.getString("NETWORK_DISCONNECTED") + ex.getMessage());
        }
        return recMessage;
    }

    /**
     * Reponds an already received message (currently only used on DispacherSocket)
     * Uses the last received packet to get the host address.
     */
    public void answer(Message message) {
        lastInPacket.setData(message.getData());
        printError(
                Resource.getString("Answer:")//14chars wide
                + lastInPacket.getAddress().getHostAddress()
                + ":" + lastInPacket.getPort() + ". ",
                message);//debug
        try {
            socket.send(lastInPacket);
        } catch (IOException ex) {
            Console.showMessageDialog(
                    Resource.getString("NETWORK_DISCONNECTED") + ex.getMessage());
        }
    }

    /**ConsoleInterface methods*/
    public DefaultStyledDocument doc = null;

    @Override
    public void setDocument(DefaultStyledDocument doc) {
        this.doc = doc;
    }

    public void printError(Message msg) {
        printError("", msg);
    }

    public void printError(String s, Message msg) {
        if (DEBUG) {
            printError(name + " " + s + " " + msg.toString());
        }
    }

    @Override
    public void printError(String s) {
        Console.println(s, System.err, doc);
    }

    @Override
    public void println(String s) {
        Console.println(s, System.out, doc);
    }
}
